﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using Islamic_influence_in_Venetian_cuture.LangResources.SpecificLang;

namespace Resources_interface_builder
{
    static class Program
    {

        static void Main(string[] args)
        {
            var tys = new Type[] 
                { 
                    typeof(Lang_ar),
                    typeof(Lang_en),
                    typeof(Lang_fa),
                    typeof(Lang_it)
                };

            var pss =
                (
                    from ty in tys
                    select ty.GetProperties().Where(p => p.Name != "ResourceManager" && p.Name != "Culture").ToList()).ToList();

            var merged = Join(pss);

            try
            {
                if (!(check(pss[0], pss[1]) && check(pss[1], pss[2]) && check(pss[2], pss[3])))
                    throw new Exception("Error in resource files");

            }
            catch (Exception)
            {
                Console.WriteLine("Merging... press");
                Console.ReadKey();
                MergeProps(pss, merged);
            }



            //var ps = tys[0].GetProperties().Where(p => p.Name != "ResourceManager" && p.Name != "Culture").ToList();


            #region code generation
            StreamWriter fout;
            try
            {
                fout = File.CreateText(@"../../../Islamic influence in Venetian cuture/LangResources/Lang.cs");
            }
            catch (Exception)
            {
                fout = File.CreateText(@"../../../../Islamic influence in Venetian cuture/LangResources/Lang.cs");
            }
            fout.WriteLine("using System;");
            fout.WriteLine("using System.ComponentModel;");
            fout.WriteLine("using Islamic_influence_in_Venetian_cuture;");
            fout.WriteLine("using Islamic_influence_in_Venetian_cuture.LangResources.SpecificLang;");
            fout.WriteLine();
            fout.WriteLine("namespace Islamic_influence_in_Venetian_cuture.LangResources\n{");
            fout.WriteLine("public class Lang : INotifyPropertyChanged\n{");
            fout.WriteLine("private static readonly System.Globalization.CultureInfo italian = new System.Globalization.CultureInfo(\"it-IT\");");
            fout.WriteLine("private static readonly System.Globalization.CultureInfo english = new System.Globalization.CultureInfo(\"en-US\");");
            fout.WriteLine();
            fout.WriteLine("private static Cultures _currentCulture;");

            fout.WriteLine("public static Cultures CurrentCulture { get { return _currentCulture; } \nset { _currentCulture = value;\n");
            fout.WriteLine("var culture = value == Cultures.Italiano ? italian : english;");
            fout.WriteLine("System.Threading.Thread.CurrentThread.CurrentCulture = culture;");
            fout.WriteLine("System.Threading.Thread.CurrentThread.CurrentUICulture = culture;");
            fout.WriteLine("if (CultureChanged != null)\n CultureChanged(); } }");
            fout.WriteLine("private static event Action CultureChanged;");
            fout.WriteLine("public Lang() { CultureChanged += RaisePropertyChanged; }");
            fout.WriteLine("public Lang(Cultures new_c) { CurrentCulture = new_c;\n CultureChanged += RaisePropertyChanged; }");

            fout.WriteLine();
            fout.WriteLine("public Cultures Culture { get { return CurrentCulture; } }");

            fout.WriteLine();
            fout.WriteLine("#region LangProperties");
            fout.WriteLine();

            foreach (var p in merged)
            {
                fout.WriteLine("public " + p.PropertyType + " " + p.Name + " { get {");
                _switch(fout, p.Name);
                fout.WriteLine("}}");// private set {}}\n");
            }

            fout.WriteLine();
            fout.WriteLine("#endregion");
            fout.WriteLine();

            fout.WriteLine("private void RaisePropertyChanged() { if (PropertyChanged != null)\n this.PropertyChanged(this, new PropertyChangedEventArgs(\"\")); }");

            fout.WriteLine("public event PropertyChangedEventHandler PropertyChanged;");

            fout.WriteLine("}}");
            fout.Close();


            #endregion
        }

        private static void MergeProps(List<List<PropertyInfo>> pss, PropertyInfo[] props)
        {
            var prop_names = props.Select(p => p.Name);
            var pss_names = (from p_c in pss select (from p in p_c select p.Name).ToList()).ToList();
            for (int i = 0; i < pss_names.Count; i++)
            {
                var p_c = pss_names[i];
                var miss = prop_names.Where(p => !p_c.Contains(p)).ToArray();
                var name = "";
                switch (i)
                {
                    case 0:
                        name = "ar";
                        break;
                    case 1:
                        name = "en";
                        break;
                    case 2:
                        name = "fa";
                        break;
                    case 3:
                        name = "it";
                        break;
                    default:
                        break;
                }
                var path = @"../../../Islamic influence in Venetian cuture/LangResources/SpecificLang/Lang_" + name + ".resx";
                var text = new List<string>();
                try
                {
                    text = File.ReadAllLines(path).ToList();
                }

                catch (Exception)
                {
                    text = File.ReadAllLines("../" + path).ToList();
                }
                text.RemoveAt(text.Count - 1);
                foreach (var m in miss)
                {
                    text.Add("  <data name=\"" + m + "\" xml:space=\"preserve\">");
                    text.Add("    <value>???</value>");
                    text.Add("  </data>");
                }
                text.Add("</root>");
                try
                {

                    File.WriteAllLines(path, text.ToArray());
                }
                catch (Exception)
                {

                    File.WriteAllLines("../" + path, text.ToArray());
                }
            }

        }

        private static bool check(List<PropertyInfo> fst, List<PropertyInfo> snd)
        {
            if (fst.Count != snd.Count)
                return false;
            for (int i = 0; i < fst.Count; i++)
            {
                if (!fst[i].MyEquals(snd[i]))
                    return false;
            }
            return true;
        }

        private static void _switch(StreamWriter fout, string prop)
        {
            fout.WriteLine("switch (CurrentCulture) {");
            fout.WriteLine("case Cultures.English: return Lang_en." + prop + ";");
            fout.WriteLine("case Cultures.Italiano: return Lang_it." + prop + ";");
            fout.WriteLine("case Cultures.Arabic: return Lang_ar." + prop + ".reverse();");
            fout.WriteLine("case Cultures.Persian: return Lang_fa." + prop + ".reverse();");
            fout.WriteLine("default: return Lang_en." + prop + ";");
            fout.WriteLine("}");
        }

        public static int IndexOf<T>(this T[] array, Func<T, bool> cond)
        {
            for (int i = 0; i < array.Length; i++)
            {
                if (cond(array[i]))
                    return i;
            }
            return -1;
        }

        internal static bool MyEquals(this PropertyInfo p1, PropertyInfo p2)
        {
            return p1.Name == p2.Name && p1.PropertyType == p2.PropertyType;
        }

        private static PropertyInfo[] Join(IEnumerable<IEnumerable<PropertyInfo>> props)
        {
            var groups = (from c_p in props from p in c_p select p).GroupBy(p => p.Name);
            foreach (var g in groups)
            {
                if (g.Where(p => p.PropertyType != g.First().PropertyType).Count() != 0)
                    throw new Exception("Error in resource files");
            }
            return groups.Select(grp => grp.First()).ToArray();
        }
    }
}
